const express = require('express')
const multer = require('multer')
const path = require('path')
const cors = require('cors')
const iconv = require('iconv-lite')
const fs = require('fs')
const app = express()
const setupWs = require('./wsServer')
const setupWsForwarder = require('./wsForwarder')


//通过.env获取port
const port = process.env.PORT || 8089
const server = require('http').createServer(app)
// 设置原始WebSocket服务
setupWs(server)
// 启动独立的WebSocket转发服务
setupWsForwarder()

// 创建上传目录
const UPLOAD_DIR = 'uploads'
if (!fs.existsSync(UPLOAD_DIR)) {
  fs.mkdirSync(UPLOAD_DIR)
}
//创建日志目录
if (!fs.existsSync('logs')) {
  fs.mkdirSync('logs')
}

//获取UPLOAD_DIR下的所有文件名，将其存储成一个Hash值
const fileHash = {}
for (const file of fs.readdirSync(UPLOAD_DIR)) {
  fileHash[file] = true
}

// 文件存储配置
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, UPLOAD_DIR)
  },
  filename: (req, file, cb) => {
    try {
      // 单次解码：从latin1转换为utf8
      const decodedName = Buffer.from(file.originalname, 'latin1').toString('utf8')
      // Unicode规范化并替换非法字符
      const normalized = decodedName.normalize('NFC')
      const safeName = normalized.replace(/[<>:"/\\|?*]/g, '_')
      cb(null, `${safeName}`)
    } catch (err) {
      cb(err)
    }
  }
})
const formatter = new Intl.DateTimeFormat('zh-CN', {
  year: 'numeric',
  month: '2-digit',
  day: '2-digit',
  hour: '2-digit',
  minute: '2-digit',
  second: '2-digit',
  hour12: false // 使用 24 小时制
})

const formattedDate = (date) => formatter.format(date)
  .replace(/\//g, '-') // 将斜杠替换为短横
  .replace(/(\d{2}):(\d{2}):(\d{2})/, '$1:$2:$3') // 可选，确保格式一致
//日志管理
const morgan = require('morgan')
const accessLogsPath = path.join(__dirname, 'logs/access.log')
const warnLogsPath = path.join(__dirname, 'logs/warn.log')
const errorLogsPath = path.join(__dirname, 'logs/error.log')
app.use(morgan('combined', {
  stream: fs.createWriteStream(accessLogsPath, { flags: 'a' })
}))

//跨域处理
app.use(cors({
  origin: '*',
  methods: ['GET', 'POST', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  optionsSuccessStatus: 204
}))
const warnLog = (message) => {
  fs.appendFileSync(warnLogsPath, `warn ${formattedDate(Date.now())} - ${message}\n`)
}
const errorLog = (message) => {
  fs.appendFileSync(errorLogsPath, `error ${formattedDate(Date.now())} - ${message}\n`)
}
const logger = (message) => {
  fs.appendFileSync(accessLogsPath, `info ${formattedDate(Date.now())} - ${message}\n`)
}
// 文件过滤
const fileFilter = (req, file, cb) => {
  const ext = path.extname(file.originalname).toLowerCase()
  const allowedTypes = ['.fbx', '.txt', '.jpg'] // 自定义允许类型
  allowedTypes.includes(ext) ? cb(null, true) : cb(new Error('非法文件类型'))
}

// 上传中间件
const upload = multer({
  storage,
  limits: { fileSize: 1024 * 1024 * 500 }, // 500MB限制
  fileFilter,
  busboy: {
    defCharset: 'utf8' // 新增配置
  }
})

app.post('/api/upload', upload.single('file'), (req, res) => {
  if (!req.file) {
    return respondError(res, 400, '未选择文件', '未选择文件')
  }
  if (fileHash[req.file.filename])
    return respondError(res, 400, '文件已存在', '文件已存在')

  // 验证文件路径安全
  const filePath = path.join(UPLOAD_DIR, req.file.filename)
  const resolvePath = path.resolve(filePath)
  if (filePath.indexOf(resolvePath) !== -1) {
    return respondError(res, 400, '非法文件路径', '尝试访问上传目录外的文件')
  }

  respondSuccess(res, {
    filename: req.file.filename,
    size: req.file.size,
    path: `/download/${req.file.filename}`
  })
})

// 辅助方法
function respondError (res, status, message, logMessage) {
  errorLog(logMessage)
  res.status(status).json({ error: message })
}

function respondSuccess (res, data) {
  logger(`文件上传成功: ${data.filename}`)
  res.json({ success: true, ...data })
}

app.post('/api/stream-upload', (req, res) => {
  const filename = req.headers['x-file-name']
  const writeStream = fs.createWriteStream(path.join(UPLOAD_DIR, filename))

  req.pipe(writeStream)
    .on('finish', () => res.json({ success: true }))
    .on('error', (err) => res.status(500).send(err.message))
})
// 处理文件下载
app.get('/download/:filename', (req, res) => {
  const filename = req.query.originalname || req.params.filename
  const filePath = path.join(UPLOAD_DIR, filename)

  if (!fs.existsSync(filePath)) {
    return res.status(404).send('文件不存在')
  }

  const resolvePath = path.resolve(filePath)
  const filePathIndex = resolvePath.indexOf(filePath)
  // 安全校验
  if (filePathIndex === -1) {
    return res.status(403).send('非法访问')
  }
  // const encodedName = encodeURIComponent(filename);
  // res.setHeader(
  //   'Content-Disposition',
  //   `attachment; filename="${encodedName}"; filename*=UTF-8''${encodedName}`
  // );

  // fs.createReadStream(filePath).pipe(res);
  res.download(filePath, filename)
})

// 静态文件服务（可选）
app.use(express.static('public'))

// 错误处理中间件
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send(err.message)
})

server.listen(port, () => {
  //写入日志,不要覆盖日志，在日志后追加日志，每条日志结束增加换行
  logger(`服务运行在 http://localhost:${port}\n`)
})
module.exports = app
